/**     
 * @Title: ShiroConfig.java   
 * @Package com.yitong.spring.shiro   
 * @Description: TODO
 * @author weiwei 
 * @date 2017年7月21日 下午3:57:34   
 * @version V1.0     
 */
package com.yitong.spring.shiro;

import java.util.HashMap;
import java.util.Map;

import javax.servlet.DispatcherType;
import javax.servlet.Filter;

import org.apache.shiro.spring.LifecycleBeanPostProcessor;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.filter.DelegatingFilterProxy;

import com.yitong.spring.filter.AuthcTokenAuthenticationFilter;
import com.yitong.spring.filter.SessionIdFilter;
import com.yitong.spring.redis.RedisCacheManager;
import com.yitong.spring.web.ParameterBaseWebSessionManager;

import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;

/**
 * @ClassName: ShiroConfig
 * @Description: TODO
 * @author weiwei
 * @date 2017年7月21日 下午3:57:34
 * 
 */
@Configuration
public class ShiroConfig {

	private final static Logger LOGGER = LoggerFactory.getLogger(ShiroConfig.class);

	@Bean
	public ShiroRedisPropertySource getShiroRedisPropertySource() {
		ShiroRedisPropertySource shiroRedisPropertySource = new ShiroRedisPropertySource();
		return shiroRedisPropertySource;
	}

	@Bean
	public LifecycleBeanPostProcessor getLifecycleBeanPostProcessor() {
		return new LifecycleBeanPostProcessor();
	}

	@Bean(name = "securityManager")
	public DefaultWebSecurityManager securityManager() {
		DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
		securityManager.setSessionManager(defaultWebSessionManager());
		securityManager.setCacheManager(redisCacheManager());
		return securityManager;
	}

	@Bean(name = "sessionManager")
	public ParameterBaseWebSessionManager defaultWebSessionManager() {
		ParameterBaseWebSessionManager sessionManager = new ParameterBaseWebSessionManager();
		sessionManager.setCacheManager(redisCacheManager());
		// Session timeout 7days:604800000L 30days:2592000000L
		sessionManager.setGlobalSessionTimeout(604800000L);
		sessionManager.setDeleteInvalidSessions(true);
		sessionManager.setSessionValidationSchedulerEnabled(true);
		sessionManager.setDeleteInvalidSessions(true);
		return sessionManager;
	}

	@Bean(name = "shrioRedisCacheManager")
	public RedisCacheManager redisCacheManager() {
		RedisCacheManager cacheManager = new RedisCacheManager(redisPoolFactory());
		return cacheManager;
	}

	@Bean
	public JedisPool redisPoolFactory() {
		ShiroRedisPropertySource source = getShiroRedisPropertySource();
		LOGGER.debug("ShiroRedisPropertySource info {}", source);
		JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
		jedisPoolConfig.setMaxIdle(source.getMaxIdle());
		jedisPoolConfig.setMaxWaitMillis(source.getMaxWait());
		jedisPoolConfig.setMinIdle(source.getMinIdle());
		jedisPoolConfig.setMaxTotal(source.getMaxTotal());
		JedisPool jedisPool = new JedisPool(jedisPoolConfig, source.getHost(), source.getPort(), source.getTimeout(),
				source.getPassword(), source.getDatabase());
		return jedisPool;
	}

	@Bean
	public AuthorizationAttributeSourceAdvisor getAuthorizationAttributeSourceAdvisor() {
		AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
		authorizationAttributeSourceAdvisor.setSecurityManager(securityManager());
		return authorizationAttributeSourceAdvisor;
	}

	@Bean
	public DefaultAdvisorAutoProxyCreator getDefaultAdvisorAutoProxyCreator() {
		DefaultAdvisorAutoProxyCreator daap = new DefaultAdvisorAutoProxyCreator();
		daap.setProxyTargetClass(true);
		return daap;
	}

//	@Bean(name = "shrioRedisCacheManager")
//	@DependsOn(value = "redisTemplate")
//	public ShrioRedisCacheManager redisCacheManager() {
//		ShrioRedisCacheManager cacheManager = new ShrioRedisCacheManager(redisTemplate());
//		return cacheManager;
//	}
//
//	@Bean(name = "redisTemplate")
//	public RedisTemplate<byte[], Object> redisTemplate() {
//		RedisTemplate<byte[], Object> template = new RedisTemplate<>();
//		template.setConnectionFactory(connectionFactory());
//		return template;
//	}
//
//	@Bean
//	public JedisConnectionFactory connectionFactory() {
//		ShiroRedisPropertySource source = getShiroRedisPropertySource();
//		LOGGER.debug("ShiroRedisPropertySource info {}", source);
//		JedisConnectionFactory conn = new JedisConnectionFactory();
//		conn.setDatabase(source.getDatabase());
//		conn.setHostName(source.getHost());
//		conn.setPassword(source.getPassword());
//		conn.setPort(source.getPort());
//		conn.setTimeout(source.getTimeout());
//		return conn;
//	}

	@Bean
	public FilterRegistrationBean delegatingFilterProxy() {
		FilterRegistrationBean filterRegistration = new FilterRegistrationBean();
		filterRegistration.setFilter(new DelegatingFilterProxy("shiroFilter"));
		filterRegistration.setEnabled(true);
		filterRegistration.addUrlPatterns("/*");
		filterRegistration.setDispatcherTypes(DispatcherType.REQUEST);
		return filterRegistration;
	}

	@Bean("shiroFilter")
	public ShiroFilterFactoryBean shiroFilterFactoryBean() {
		ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
		shiroFilterFactoryBean.setSecurityManager(securityManager());
		shiroFilterFactoryBean.setLoginUrl("/v1/user/login");
		shiroFilterFactoryBean.setSuccessUrl("/index");
		shiroFilterFactoryBean.setUnauthorizedUrl("/403");
		// filter
		Map<String, Filter> filters = shiroFilterFactoryBean.getFilters();// 获取filters
		filters.put("sid", new SessionIdFilter());// redis存session过滤器
		filters.put("authc", new AuthcTokenAuthenticationFilter());// 验证码过滤器
		// url
		Map<String, String> filterChainDefinitionMap = new HashMap<String, String>();
		filterChainDefinitionMap.put("/v1/user/logout", "sid");
		filterChainDefinitionMap.put("/v1/user/**", "authc, sid");
		// filterChainDefinitionMap.put("/v1/user/**", "sid");
		filterChainDefinitionMap.put("/**", "sid");
		shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
		return shiroFilterFactoryBean;
	}

}
